﻿using System;
using System.Collections.Generic;
//===================================================================
//
//            本代码由David Wang原创，仅用于学习之用
//        All these codes can only be used to learning 
//
//                       2017.08.15                
//
//===================================================================
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace perlin
{
    public partial class Form1 : Form
    {
        #region Helper
        [DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr hWnd);
        [DllImport("user32.dll")]
        static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
        [DllImport("gdi32.dll")]
        static extern int GetPixel(IntPtr hDC, int x, int y);
        [DllImport("gdi32.dll")]
        static extern int SetPixel(IntPtr hDC, int x, int y, int color);

        static public Color GetPixel(Control control, int x, int y)
        {
            Color color = Color.Empty;
            if (control != null)
            {
                IntPtr hDC = GetDC(control.Handle);
                int colorRef = GetPixel(hDC, x, y);
                color = Color.FromArgb(
                    (int)(colorRef & 0x000000FF),
                    (int)(colorRef & 0x0000FF00) >> 8,
                    (int)(colorRef & 0x00FF0000) >> 16);
                ReleaseDC(control.Handle, hDC);
            }
            return color;
        }

        #region 常量
        Graphics g;
        static int clientWidth;
        static int clientHeith;
        DavidWang.PerlinNoise1D perlinNoise = new DavidWang.PerlinNoise1D();
        DavidWang.PerlinNoise2D perlinNoise2D = new DavidWang.PerlinNoise2D();
        DavidWang.PerlinNoise3D perlinNoise3D = new DavidWang.PerlinNoise3D();
        DavidWang.PerlinNoise4D perlinNoise4D = new DavidWang.PerlinNoise4D();
        #endregion
        public Form1()
        {
            InitializeComponent();
            g = this.CreateGraphics();
            clientWidth = ClientSize.Width;
            clientHeith = ClientSize.Height;
            /////  for 2D
            perlinNoise2D.Frequency = 0.005f; //1.0f / clientWidth; //0.01f ;
            ////   for 3D 
            perlinNoise3D.Frequency = 0.05f;
            /////  for 4D
            perlinNoise4D.Frequency = 0.05f;
        }

        void drawPoint(System.IntPtr hDC,Point mypoint)
        {
            Color color = Color.Red;
            SetPixel(hDC, mypoint.X,mypoint.Y, color.R | color.G << 8 | color.B << 16);
        }
        void drawPoint(System.IntPtr hDC, Point mypoint, Color color)
        {
            SetPixel(hDC, mypoint.X, mypoint.Y, color.R | color.G << 8 | color.B << 16);
        }
        
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            g.Dispose();
            
        }

        Color lerpColor(Color left, Color right, float amount)
        {
            return Color.FromArgb(left.R + (int)((right.R - left.R) * amount), left.G + (int)((right.G - left.G)), left.B + (int)((right.B - left.B)));
        }
        #endregion
        private void button1_Click(object sender, EventArgs e)
        {
            g.Clear(Color.White);
            #region 1D Perlin Noise
            #region 使用点而不是线
            
            System.IntPtr hDC = g.GetHdc();
            int y = 0;            
            for (int x = 1; x <= clientWidth; x++)
            {
                y = perlinNoise.Perlin(x) + 100;
                drawPoint(hDC, new Point(x, y));
            }            
            g.ReleaseHdc();
            
            #endregion
            #region 使用线而不是离散的点
            /*
            Pen p = new Pen(Color.Red, 1.0f);
            int[] PostionY = new int[clientWidth];
            for (int x = 1; x <= clientWidth; x++)
            {
                PostionY[x-1] = perlinNoise.Perlin(x) + 100;
            }
            for (int x = 0; x < clientWidth-1; x++)
            {
                g.DrawLine(p, new Point(x + 1, PostionY[x]), new Point(x + 2, PostionY[x + 1]));
             }
             */
            #endregion
            #region 使用分形布朗运动叠加(点)
            /*
            System.IntPtr hDC = g.GetHdc();
            int[] PostionY = new int[clientWidth];
            float tFrequency = perlinNoise.Frequency;
            float tAmplitude = perlinNoise.Amplitude;
            const int octaves = 4;
            float lacunarity = 2.0f;
            float gain = 0.5f;
            for (int i = 0; i < octaves; i++)
            {
                for (int x = 1; x <= clientWidth; x++)
                {
                    PostionY[x-1] += perlinNoise.Perlin(x);
                }
                perlinNoise.Frequency *= lacunarity;
                perlinNoise.Amplitude *= gain;                
            }
            perlinNoise.Frequency = tFrequency;
            perlinNoise.Amplitude = tAmplitude;
            for (int x = 1; x < clientWidth; x++)
            {
               // g.DrawLine(p, new Point(x + 1, PostionY[x]), new Point(x + 2, PostionY[x + 1]));
                drawPoint(hDC, new Point(x, PostionY[x-1]));
            }
            g.ReleaseHdc();
            */
            #endregion
            #region 使用分形布朗运动叠加(线)
            /*
            Pen p = new Pen(Color.Red, 1.0f);
            int[] PostionY = new int[clientWidth];
            float tFrequency = perlinNoise.Frequency;
            float tAmplitude = perlinNoise.Amplitude;

            const int octaves = 4;
            float lacunarity = 2.0f;
            float gain = 0.5f;
            for (int i = 0; i < octaves; i++)
            {
                for (int x = 1; x <= clientWidth; x++)
                {
                    PostionY[x - 1] += perlinNoise.Perlin(x);
                }
                perlinNoise.Frequency *= lacunarity;
                perlinNoise.Amplitude *= gain;                
            }
            perlinNoise.Frequency = tFrequency;
            perlinNoise.Amplitude = tAmplitude;

            for (int x = 0; x < clientWidth - 1; x++)
            { 
                g.DrawLine(p, new Point(x + 1, PostionY[x]), new Point(x + 2, PostionY[x + 1]));
            }
           */
            #endregion
            #endregion
            #region 2D Perlin Noise
            #region 单形Perlin噪声
            /*
            System.IntPtr hDC = g.GetHdc();            
            float min = 100000;
            float max = -100000;
            float[,] map = new float[clientWidth, clientHeith];
            for (int x = 1; x <= clientWidth; x++)
            {
                for (int y = 1; y <= clientHeith; y++)
                {
                    map[x-1,y-1] = perlinNoise2D.Perlin(x, y);
                    if (map[x - 1, y - 1] < min)
                        min = map[x - 1, y - 1];
                    if (map[x - 1, y - 1] > max)
                        max = map[x - 1, y - 1];
                }
            }

            Color landlow = Color.FromArgb(2, 66, 2),
            landhigh = Color.FromArgb(131, 180, 114),
            waterlow = Color.FromArgb(0, 13, 68),
            waterhigh = Color.FromArgb(0, 143, 240),
            mountlow = Color.FromArgb(169, 160, 150),
            mounthigh = Color.FromArgb(206, 210, 210);
            Color newColor;
            float diff = max - min,
            flood = 0.5f,
            mount = 0.85f;
            flood *= diff;
            mount *= diff;
            for (int x = 1; x <= clientWidth; x++)
            {
                for(int y = 1;y <= clientHeith; y++)
                {
                    map[x-1,y-1] -= min;
                    if (map[x-1,y-1] < flood)
                        newColor = lerpColor(waterlow, waterhigh, map[x-1,y-1] / flood);
                    else if (map[x-1,y-1] > mount)
                        newColor = lerpColor(mountlow, mounthigh, (map[x-1,y-1] - mount) / (diff - mount));
                    else
                        newColor = lerpColor(landlow, landhigh, (map[x-1,y-1] - flood) / (mount - flood));
                    drawPoint(hDC, new Point(x, y), newColor);
                }
            }
            g.ReleaseHdc();
            */
            #endregion
            #region 分形布朗运动
            /*
            float min = 100000;
            float max = -100000;
            int octaves = 4;
            float tFrequency = perlinNoise2D.Frequency;
            float tAmplitude = perlinNoise2D.Amplitude;
            float lacunarity = 2.0f;
            float gain = 0.5f;
            float[,] map = new float[clientWidth, clientHeith];
            for (int i = 0; i < octaves; i++)
            {
                for (int x = 1; x <= clientWidth; x++)
                {
                    for (int y = 1; y <= clientHeith; y++)
                    {
                        map[x - 1, y - 1] += perlinNoise2D.Perlin(x, y);   
                        if (map[x - 1, y - 1] < min)
                            min = map[x - 1, y - 1];
                        if (map[x - 1, y - 1] > max)
                            max = map[x - 1, y - 1];
                    }
                }
                perlinNoise2D.Amplitude *= gain;
                perlinNoise2D.Frequency *= lacunarity;
            }
            perlinNoise2D.Frequency = tFrequency;
            perlinNoise2D.Amplitude = tAmplitude;

            Color landlow = Color.FromArgb(2, 66, 2),
            landhigh = Color.FromArgb(131, 180, 114),
            waterlow = Color.FromArgb(0, 13, 68),
            waterhigh = Color.FromArgb(0, 143, 240),
            mountlow = Color.FromArgb(169, 160, 150),
            mounthigh = Color.FromArgb(206, 210, 210);
            Color newColor;
            float diff = max - min,
            flood = 0.4f,
            mount = 0.85f;
            flood *= diff;
            mount *= diff;
            for (int x = 1; x <= clientWidth; x++)
            {
                for (int y = 1; y <= clientHeith; y++)
                {
                    map[x - 1, y - 1] -= min;
                    if (map[x - 1, y - 1] < flood)
                        newColor = lerpColor(waterlow, waterhigh, map[x - 1, y - 1] / flood);
                    else if (map[x - 1, y - 1] > mount)
                        newColor = lerpColor(mountlow, mounthigh, (map[x - 1, y - 1] - mount) / (diff - mount));
                    else
                        newColor = lerpColor(landlow, landhigh, (map[x - 1, y - 1] - flood) / (mount - flood));
                    drawPoint(hDC, new Point(x, y), newColor);
                }
            }
            g.ReleaseHdc();
            */
            #endregion
            #endregion
            #region 3D Perlin Noise
            #region 单形Perlin噪声
            /*
            System.IntPtr hDC = g.GetHdc();            
            float min = 100000;
            float max = -100000;
            int mapSize = 200;
            float[,,] map = new float[mapSize, mapSize,mapSize];
            for (int x = 0; x < mapSize; x++)
            {
                for (int y = 0; y < mapSize; y++)
                {
                    for (int z = 0; z < mapSize; z++)
                    {
                        map[x, y, z] = perlinNoise3D.Perlin(x, y, z);
                        if (map[x, y, z] < min)
                            min = map[x, y, z];
                        if (map[x, y, z] > max)
                            max = map[x, y, z];
                    }
                }
            }

            Color landlow = Color.FromArgb(2, 66, 2),
            landhigh = Color.FromArgb(131, 180, 114),
            waterlow = Color.FromArgb(0, 13, 68),
            waterhigh = Color.FromArgb(0, 143, 240),
            mountlow = Color.FromArgb(169, 160, 150),
            mounthigh = Color.FromArgb(206, 210, 210);
            Color newColor;
            float diff = max - min,
            flood = 0.5f,
            mount = 0.85f;
            flood *= diff;
            mount *= diff;
            for (int x = 0; x < mapSize; x++)
            {
                for(int y = 0;y < mapSize; y++)
                {
                    for (int z = 0; z < mapSize; z++)
                    {
                        map[x, y, z] -= min;
                        if (map[x, y ,z] < flood)
                            newColor = lerpColor(waterlow, waterhigh, map[x , y ,z] / flood);
                        else if (map[x, y,z] > mount)
                            newColor = lerpColor(mountlow, mounthigh, (map[x, y, z] - mount) / (diff - mount));
                        else
                            newColor = lerpColor(landlow, landhigh, (map[x , y , z] - flood) / (mount - flood));
                        drawPoint(hDC, new Point(y+100, z+100), newColor);
                    }
                }
            }
            g.ReleaseHdc();
            */
            #endregion
            #endregion

            #region 4D Perlin Noise
            #region 单形Perlin噪声
            /*
            System.IntPtr hDC = g.GetHdc();            
            float min = 100000;
            float max = -100000;
            int mapSize = 100;
            float[,,,] map = new float[mapSize, mapSize,mapSize,mapSize];
            for (int x = 0; x < mapSize; x++)
            {
                for (int y = 0; y < mapSize; y++)
                {
                    for (int z = 0; z < mapSize; z++)
                    {
                        for (int w = 0; w < mapSize; w++)
                        {
                            map[x, y, z,w] = perlinNoise4D.Perlin(x, y, z,w);
                            if (map[x, y, z,w] < min)
                                min = map[x, y, z,w];
                            if (map[x, y, z,w] > max)
                                max = map[x, y, z,w];
                        }
                    }
                }
            }

            Color landlow = Color.FromArgb(2, 66, 2),
            landhigh = Color.FromArgb(131, 180, 114),
            waterlow = Color.FromArgb(0, 13, 68),
            waterhigh = Color.FromArgb(0, 143, 240),
            mountlow = Color.FromArgb(169, 160, 150),
            mounthigh = Color.FromArgb(206, 210, 210);
            Color newColor;
            float diff = max - min,
            flood = 0.5f,
            mount = 0.85f;
            flood *= diff;
            mount *= diff;
            int depth = 0;
            for (int x = 0; x < mapSize; x++)
            {
                for(int y = 0;y < mapSize; y++)
                {
                    for (int z = 0; z < mapSize; z++)
                    {
                        
                        map[x, y, z, depth] -= min;
                        if (map[x, y ,z, depth] < flood)
                            newColor = lerpColor(waterlow, waterhigh, map[x , y ,z, depth] / flood);
                        else if (map[x, y,z, depth] > mount)
                            newColor = lerpColor(mountlow, mounthigh, (map[x, y, z, depth] - mount) / (diff - mount));
                        else
                            newColor = lerpColor(landlow, landhigh, (map[x , y , z, depth] - flood) / (mount - flood));
                        drawPoint(hDC, new Point(y+100, z+100), newColor);
                    }
                }
            }
            g.ReleaseHdc();
            */
            #endregion
            #endregion
        }


    }

}
